package com.alogic.matcher;

import com.alogic.matcher.impl.*;
import com.anysoft.util.Properties;
import com.google.re2j.Matcher;
import com.google.re2j.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

/**
 * 工厂类
 *
 * @since 1.6.12.57 [20200103]
 *
 *
 * @version 1.6.13.4 [20200514 duanyy] <br>
 *  - 修正正则表达式错误 <br>
 *
 * @version 1.6.13.7 [20200720 duanyy] <br>
 *  - 增加bucket插件
 */
public class MatcherFactory {

    /**
     * a slf4j logger
     */
    protected static Logger LOG = LoggerFactory.getLogger(CommonMatcher.class);

    /**
     * 类名映射
     */
    protected static Map<String,Class<? extends CommonMatcher>> classMappings
            = new HashMap<String,Class<? extends CommonMatcher>>();

    /**
     * 分离匹配器和表达式
     */
    protected static Pattern matcherAndExpr = Pattern.compile("^\\(([\\w]*)\\)(.*)$");

    protected static String DFT_MATCHER = "re2";

    /**
     * 注册匹配器
     * @param name 名称
     * @param clazz 实现类
     */
    public static void register(String name,Class<? extends CommonMatcher> clazz){
        if (StringUtils.isNotEmpty(name) && clazz != null){
            classMappings.put(name,clazz);
        }
    }

    /**
     * 注销匹配器
     * @param name 匹配器名称
     */
    public static void unregister(String name){
        if (StringUtils.isNotEmpty(name)) {
            classMappings.remove(name);
        }
    }

    public static CommonMatcher getMatcher(String pattern, Properties p){
        String matcherId = DFT_MATCHER;
        String regex = pattern;

        Matcher matcher = matcherAndExpr.matcher(pattern);
        if (matcher.find()){
            matcherId = matcher.group(1);
            regex = matcher.group(2);
        }

        if (StringUtils.isEmpty(matcherId)){
            matcherId = DFT_MATCHER;
        }
        matcherId = matcherId.toLowerCase();


        Class<? extends CommonMatcher> clazz = getMatcherClass(matcherId);
        try{
            Constructor<? extends CommonMatcher> constructor = clazz.getConstructor(
                    new Class[]{String.class,Properties.class}
            );
            return constructor.newInstance(new Object[]{regex,p});
        }catch (Exception ex){
            LOG.warn("Can not create matcher instance:" + matcherId);
            return new Wildcard(regex,p);
        }
    }

    protected static Class<? extends CommonMatcher> getMatcherClass(String matcherId){
        Class<? extends CommonMatcher> found = classMappings.get(matcherId);
        return found == null?Wildcard.class:found;
    }

    static {
        register("re2", Re2.class);
        register("regex", Re2.class);
        register("wildcard", Wildcard.class);
        register("exact", Exact.class);
        register("cidr", IpSegment.class);
        register("ip", IpSegment.class);
        register("bucket", TimeBucketMatcher.class);
    }
}